import { Group } from 'src/modules/group/entities/group.entity';
import { MatchInfo } from 'src/modules/match/entities/match.entity';
import { genTeamSubMatches } from './createRound';
import { EventToPlayer } from 'src/modules/event-to-player/entities/event-to-player.entity';
import {
  MatchPlayerStatusEnum,
  registrationIndexInitValue,
} from 'src/common/constant/enums';
import { getE2PCount } from 'src/common/utils/matchUtils';
import { Stage } from 'src/modules/stage/entities/stage.entity';

const generateLoopMatch = (
  groupLoopIndex: number,
  rangeMin: number,
  rangeMax: number,
  otherMatchParam: Partial<MatchInfo>,
): Array<Partial<MatchInfo>> => {
  const matchList = [];
  const matchCount = (rangeMax / 1 - rangeMin / 1) / 2;
  while (matchList.length < matchCount) {
    const newMatch = { rangeMin, rangeMax, groupLoopIndex, ...otherMatchParam };
    matchList.push(newMatch);
  }
  return matchList;
};

const getRelatedMatchLoops = (distWinner, from = 1, to): Array<string> => {
  let curMax = to;
  let curMinx = from;
  const relatedMatchLoops = [];
  while (curMax >= distWinner) {
    relatedMatchLoops.push(`${curMinx}-${curMax}`);
    const middleIdx = (curMax - curMinx + 1) / 2;
    const middle = curMinx + middleIdx;
    if (distWinner < middle) {
      curMax = middle - 1;
    } else {
      curMinx = middle;
    }
    if (curMax - curMinx === 1) {
      relatedMatchLoops.push(`${curMinx}-${curMax}`);
      break;
    }
  }
  return relatedMatchLoops;
};

const createElimation = (
  playerCount: number,
  totalPlayers: Array<EventToPlayer>,
  winnerCount: number = 2,
  otherMatchParam: Partial<MatchInfo>,
) => {
  const totalPlayerCount = playerCount;
  const totalPlayerMap = totalPlayers.reduce((acc, cur, idx) => {
    acc[cur.registrationIndex] = cur;
    return acc;
  }, {});
  let curSearchWinner = 1;
  const matchGraph = {};
  let baseMatchList: Array<Partial<MatchInfo>> = null;
  let groupMatchIndex = 1;
  let groupLoopIndex = 1;
  while (curSearchWinner <= winnerCount) {
    const relatedMatchLoops = getRelatedMatchLoops(
      curSearchWinner,
      1,
      totalPlayerCount,
    );
    relatedMatchLoops.forEach((v, k) => {
      if (!matchGraph[v]) {
        const [min, max] = v.split('-');
        matchGraph[v] = generateLoopMatch(
          groupLoopIndex++,
          parseInt(min),
          parseInt(max),
          otherMatchParam,
        );
        matchGraph[v].forEach((v) => (v.groupMatchIndex = groupMatchIndex++));
        if (!baseMatchList) {
          baseMatchList = matchGraph[v];
          // baseMatchList 应该将homePlayer和awayPlayer都设
          let playerIndex = registrationIndexInitValue;
          baseMatchList.forEach((v) => {
            v.homePlayer = totalPlayerMap[`${playerIndex++}`];
            v.awayPlayer = totalPlayerMap[`${playerIndex++}`];
          });
        }
        const lastRelatedLoops = relatedMatchLoops[k - 1];
        if (lastRelatedLoops) {
          const [lastMin] = lastRelatedLoops.split('-');
          const nextStatusPlayerType = lastMin === min ? 'winner' : 'loser';
          const lastLoopMatches = matchGraph[lastRelatedLoops]; // 上一轮的比赛列表
          matchGraph[v].forEach((match, i) => {
            if (nextStatusPlayerType === 'winner') {
              lastLoopMatches[2 * i].nextWinnerMatchIndex =
                match.groupMatchIndex;
              lastLoopMatches[2 * i + 1].nextWinnerMatchIndex =
                match.groupMatchIndex;
            } else {
              lastLoopMatches[2 * i].nextLoserMatchIndex =
                match.groupMatchIndex;
              lastLoopMatches[2 * i + 1].nextLoserMatchIndex =
                match.groupMatchIndex;
            }
          });
        }
      }
    });
    curSearchWinner++;
  }
  const retMatchList = [];
  Object.keys(matchGraph).forEach((key) => {
    retMatchList.push(...matchGraph[key]);
  });
  return retMatchList;
};

export const handleElimationStage = (
  stageInfo: Stage,
  totalPlayers: Array<EventToPlayer>,
  isTeamEvent?: boolean,
) => {
  const {
    eliminationWinnerCount,
    gameRuleId,
    rallyRuleId,
    mustFinishMaxCountGame,
    mustFinishMaxCountMatch,
    tournamentId,
    categoryId,
    event,
    playerCount,
    type: stageType,
    mustCheckIn,
    createBy,
    updateBy,
  } = stageInfo;
  // const players = totalPlayers.map((v) => v.registrationIndex);
  const matchTemplate = {
    type: event.type,
    homePlayerRally: 0,
    awayPlayerRally: 0,
    isTeamMatch: isTeamEvent,
    createBy: createBy,
    updateBy: updateBy,
    gameRuleId,
    rallyRuleId,
    tournamentId,
    categoryId,
    eventId: event.id,
    mustFinishMaxCountGame,
    mustFinishMaxCountMatch,
    homePlayerStatus: mustCheckIn
      ? MatchPlayerStatusEnum.NotCheckIn
      : MatchPlayerStatusEnum.CheckedIn,
    awayPlayerStatus: mustCheckIn
      ? MatchPlayerStatusEnum.NotCheckIn
      : MatchPlayerStatusEnum.CheckedIn,
  };
  const matchList = createElimation(
    getE2PCount(stageType, playerCount, 1),
    totalPlayers,
    eliminationWinnerCount,
    matchTemplate,
  );
  if (isTeamEvent) {
    matchList.forEach((v) => {
      genTeamSubMatches(v, stageInfo, totalPlayers, matchTemplate);
    });
  }
  const group = new Group();
  group.createBy = stageInfo.createBy;
  group.updateBy = stageInfo.updateBy;
  group.name = '';
  group.matchInfos = matchList;
  console.log('matchList', matchList.length);
  stageInfo.groups = [group];

  return stageInfo;
};

// main(8, 6);
export default createElimation;
